import {
    _decorator,
    Component,
    Node,
    input,
    Vec3,
    EventTouch,
    EventMouse,
    Vec2,
    Quat,
    game,
    Touch,
    log,
    EventKeyboard,
    KeyCode,
    v3,
    Input,
} from 'cc';
const { ccclass, property } = _decorator;

// 静态常量，用于存放临时数据
const v2_temp1 = new Vec2();
const v2_temp2 = new Vec2();
const v3_temp1 = new Vec3();
const quat_temp = new Quat();

@ccclass('FirstPersonCamera')
export class NewComponent extends Component {
    @property
    public moveSpeed = 1;

    @property
    public rotateSpeed = 1;

    @property
    public moveSpeedShiftScale = 5;

    @property({ slide: true, range: [0.05, 0.5, 0.01] })
    public damp = 0.2;

    private _euler = new Vec3();
    private _velocity = new Vec3();
    private _position = new Vec3();

    private _inputList: Map<KeyCode, boolean> = new Map();

    start() {
        // [3]
        input.on(Input.EventType.MOUSE_WHEEL, this.onMouseWheel, this);
        input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
        input.on(Input.EventType.KEY_UP, this.onKeyUp, this);
        input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
        input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
        input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this);

        //拷贝数据
        Vec3.copy(this._euler, this.node.eulerAngles);
        Vec3.copy(this._position, this.node.position);
    }

    update(deltaTime: number) {
        // [4]
        this.moveUpdate();

        // position
        Vec3.transformQuat(v3_temp1, this._velocity, this.node.rotation);
        Vec3.scaleAndAdd(
            this._position,
            this._position,
            v3_temp1,
            this.moveSpeed,
        );
        Vec3.lerp(
            v3_temp1,
            this.node.position,
            this._position,
            deltaTime / this.damp,
        );
        this.node.setPosition(v3_temp1);

        // rotation
        Quat.fromEuler(
            quat_temp,
            this._euler.x,
            this._euler.y,
            this._euler.z,
        );
        Quat.slerp(
            quat_temp,
            this.node.rotation,
            quat_temp,
            deltaTime / this.damp,
        );
        this.node.setRotation(quat_temp);
    }

    //获取鼠标滚轮事件
    onMouseWheel(e: EventMouse) {
        // delta is positive when scroll down
        const delta = -e.getScrollY() * this.moveSpeed * 0.1;
        Vec3.transformQuat(v3_temp1, Vec3.UNIT_Z, this.node.rotation);
        Vec3.scaleAndAdd(
            this._position,
            this.node.position,
            v3_temp1,
            delta,
        );
    }

    public onTouchStart(e: EventTouch) {
        game.canvas?.requestPointerLock();
    }

    public onTouchMove(e: EventTouch) {
        e.getStartLocation(v2_temp1);

        // rotation 旋转
        e.getDelta(v2_temp2);
        this._euler.y -= v2_temp2.x * this.rotateSpeed * 0.1;
        this._euler.x += v2_temp2.y * this.rotateSpeed * 0.1;

        // position 平移
        // e.getLocation(v2_2);
        // Vec2.subtract(v2_2, v2_2, v2_1);
        // this._velocity.x = v2_2.x * 0.01;
        // this._velocity.z = -v2_2.y * 0.01;
    }

    public onTouchEnd(e: EventTouch) {
        if (document.exitPointerLock) {
            document.exitPointerLock();
        }
        e.getStartLocation(v2_temp1);
        if (v2_temp1.x < game.canvas.width * 0.4) {
            // position
            this._velocity.x = 0;
            this._velocity.z = 0;
        }
    }

    public onKeyDown(e: EventKeyboard) {
        this._inputList.set(e.keyCode, true);
    }

    public onKeyUp(e: EventKeyboard) {
        this._inputList.set(e.keyCode, false);
    }

    public reset() {
        for (let key of this._inputList.keys()) {
            key[1] = false;
        }

        //test is done
        for (let key of this._inputList.keys()) {
            log(key);
        }
    }

    moveUpdate() {
        const v = this._velocity;
        const input = this._inputList;
        v.set(0, 0, 0);
        //前进
        if (input.get(KeyCode.KEY_W) || input.get(KeyCode.ARROW_UP)) {
            v.z = -1;
        }
        //后退
        if (input.get(KeyCode.KEY_S) || input.get(KeyCode.ARROW_DOWN)) {
            v.z = 1;
        }
        if (input.get(KeyCode.KEY_A) || input.get(KeyCode.ARROW_LEFT)) {
            v.x = -1;
        }
        if (input.get(KeyCode.KEY_D) || input.get(KeyCode.ARROW_RIGHT)) {
            v.x = 1;
        }
        if (input.get(KeyCode.SPACE)) {
            v.y = 1;
        }
        if (input.get(KeyCode.CTRL_LEFT)) {
            v.y = -1;
        }
        if (input.get(KeyCode.SHIFT_LEFT)) {
            let temp = v3(
                this.moveSpeedShiftScale,
                this.moveSpeedShiftScale,
                this.moveSpeedShiftScale,
            );
            Vec3.multiply(v, v, temp);
        }
    }
}
